home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / pager.c < prev    next >
C/C++ Source or Header  |  1993-01-22  |  17KB  |  663 lines

  1. /*    SCCS Id: @(#)pager.c    3.1    92/09/01          */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /* This file contains the command routines dowhatis() and dohelp() and */
  6. /* a few other help related facilities */
  7.  
  8. #include    "hack.h"
  9.  
  10. #ifndef SEEK_SET
  11. #define SEEK_SET 0
  12. #endif
  13.  
  14. static boolean FDECL(is_swallow_sym, (UCHAR_P));
  15. static int FDECL(append_str, (char *, const char *));
  16. static void FDECL(lookat, (int, int, char *));
  17. static void FDECL(checkfile, (char *, BOOLEAN_P));
  18. static int FDECL(do_look, (BOOLEAN_P));
  19. static char NDECL(help_menu);
  20. #ifdef PORT_HELP
  21. extern void NDECL(port_help);
  22. #endif
  23.  
  24. /* Returns "true" for characters that could represent a monster's stomach. */
  25. static boolean
  26. is_swallow_sym(c)
  27.     uchar c;
  28. {
  29.     int i;
  30.     for (i = S_sw_tl; i <= S_sw_br; i++)
  31.     if (showsyms[i] == c) return TRUE;
  32.     return FALSE;
  33. }
  34.  
  35. /*
  36.  * Append new_str to the end of buf if new_str doesn't already exist as
  37.  * a substring of buf.  Return 1 if the string was appended, 0 otherwise.
  38.  * It is expected that buf is of size BUFSZ.
  39.  */
  40. static int
  41. append_str(buf, new_str)
  42.     char *buf;
  43.     const char *new_str;
  44. {
  45.     int space_left;    /* space remaining in buf */
  46.  
  47.     if (strstri(buf, new_str)) return 0;
  48.  
  49.     space_left = BUFSZ - strlen(buf) - 1;
  50.     (void) strncat(buf, " or ", space_left);
  51.     (void) strncat(buf, new_str, space_left - 4);
  52.     return 1;
  53. }
  54.  
  55. /*
  56.  * Return the name of the glyph found at (x,y).
  57.  */
  58. static void
  59. lookat(x, y, buf)
  60.     int x, y;
  61.     char *buf;
  62. {
  63.     register struct monst *mtmp;
  64.     struct trap *trap;
  65.     register char *s, *t;
  66.     int glyph;
  67.  
  68.     buf[0] = 0;
  69.     glyph = glyph_at(x,y);
  70.     if (u.ux == x && u.uy == y && canseeself()) {
  71.     Sprintf(buf, "%s called %s",
  72. #ifdef POLYSELF
  73.         u.mtimedone ? mons[u.umonnum].mname :
  74. #endif
  75.         player_mon()->mname, plname);
  76.     }
  77.     else if (u.uswallow) {
  78.     /* all locations when swallowed other than the hero are the monster */
  79.     Sprintf(buf, "interior of %s",
  80.                     Blind ? "a monster" : a_monnam(u.ustuck));
  81.     }
  82.     else if (glyph_is_monster(glyph)) {
  83.     bhitpos.x = x;
  84.     bhitpos.y = y;
  85.     mtmp = m_at(x,y);
  86.     if(mtmp != (struct monst *) 0) {
  87.         register boolean hp = (mtmp->data == &mons[PM_HIGH_PRIEST]);
  88.  
  89.         Sprintf(buf, "%s%s%s",
  90.             (!hp && mtmp->mtame && !Hallucination) ? "tame " :
  91.             (!hp && mtmp->mpeaceful && !Hallucination) ?
  92.                                                   "peaceful " : "",
  93.             (hp ? "high priest" : l_monnam(mtmp)),
  94.             u.ustuck == mtmp ?
  95. #ifdef POLYSELF
  96.             (u.mtimedone ? ", being held" :
  97. #endif
  98.             ", holding you"
  99. #ifdef POLYSELF
  100.             )
  101. #endif
  102.             : "");
  103.     }
  104.     }
  105.     else if (glyph_is_object(glyph)) {
  106.     struct obj *otmp = vobj_at(x,y);
  107.  
  108.     if(otmp == (struct obj *) 0 || otmp->otyp != glyph_to_obj(glyph)) {
  109.         if(glyph_to_obj(glyph) != STRANGE_OBJECT) {
  110.         otmp = mksobj(glyph_to_obj(glyph), FALSE, FALSE);
  111.         if(otmp->oclass == GOLD_CLASS)
  112.             otmp->quan = 2L; /* to force pluralization */
  113.         Strcpy(buf, distant_name(otmp, xname));
  114.         dealloc_obj(otmp);
  115.         }
  116.     } else
  117.         Strcpy(buf, distant_name(otmp, xname));
  118.     }
  119.     else if (glyph_is_trap(glyph)) {
  120.     if (trap = t_at(x, y)) {
  121.         if (trap->ttyp == WEB)
  122.         Strcpy(buf, "web");
  123.         else {
  124.         Strcpy(buf, traps[ Hallucination ?
  125.                      rn2(TRAPNUM-3)+3 : trap->ttyp]);
  126.         /* strip leading garbage */
  127.         for (s = buf; *s && *s != ' '; s++) ;
  128.         if (*s) ++s;
  129.         for (t = buf; *t++ = *s++; ) ;
  130.         }
  131.     }
  132.     }
  133.     else if(!glyph_is_cmap(glyph))
  134.     Strcpy(buf,"dark part of a room");
  135.     else switch(glyph_to_cmap(glyph)) {
  136.     case S_altar:
  137.         if(!In_endgame(&u.uz))
  138.         Sprintf(buf, "%s altar",
  139.         align_str(Amask2align(levl[x][y].altarmask & ~AM_SHRINE)));
  140.     else Sprintf(buf, "aligned altar");
  141.     break;
  142.     case S_ndoor:
  143.     if((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN)
  144.         Strcpy(buf,"broken door");
  145.     else
  146.         Strcpy(buf,"doorway");
  147.     break;
  148.     default:
  149.     Strcpy(buf,defsyms[glyph_to_cmap(glyph)].explanation);
  150.     break;
  151.     }
  152. }
  153.  
  154. /*
  155.  * Look in the "data" file for more info.  Called if the user typed in the
  156.  * whole name (user_typed_name == TRUE), or we've found a possible match
  157.  * with a character/glyph and flags.help is TRUE.
  158.  *
  159.  * NOTE: when (user_typed_name == FALSE), inp is considered read-only and 
  160.  *     must not be changed directly, e.g. via lcase(). Permitted are
  161.  *     functions, e.g. makesingular(), which operate on a copy of inp.
  162.  */
  163. static void
  164. checkfile(inp, user_typed_name)
  165.     char *inp;
  166.     boolean user_typed_name;
  167. {
  168.     FILE *fp;
  169.     char buf[BUFSZ];
  170.     char *ep;
  171.     long txt_offset;
  172.     boolean found_in_file = FALSE;
  173.  
  174.     fp = fopen_datafile(DATAFILE, "r");
  175.     if (!fp) {
  176.     pline("Cannot open data file!");
  177.     return;
  178.     }
  179.  
  180.     if (!strncmp(inp, "interior of ", 12))
  181.     inp += 12;
  182.     if (!strncmp(inp, "a ", 2))
  183.     inp += 2;
  184.     else if (!strncmp(inp, "an ", 3))
  185.     inp += 3;
  186.     else if (!strncmp(inp, "the ", 4))
  187.     inp += 4;
  188.     if (!strncmp(inp, "tame ", 5))
  189.     inp += 5;
  190.     else if (!strncmp(inp, "peaceful ", 9))
  191.     inp += 9;
  192.     if (!strncmp(inp, "invisible ", 10))
  193.     inp += 10;
  194.  
  195.     /* Make sure the name is non-empty. */
  196.     if (*inp) {
  197.     /* adjust the input to remove "named " and convert to lower case */
  198.     char *alt = 0;    /* alternate description */
  199.     if ((ep = strstri(inp, " named ")) != 0)
  200.         alt = ep + 7;
  201.     else
  202.         ep = strstri(inp, " called ");
  203.     if (ep) *ep = '\0';
  204.     if (user_typed_name)
  205.         (void) lcase(inp);
  206.  
  207.     /*
  208.      * If the object is named, then the name is the alternate description;
  209.      * otherwise, the result of makesingular() applied to the name is. This
  210.      * isn't strictly optimal, but named objects of interest to the user
  211.      * will usually be found under their name, rather than under their
  212.      * object type, so looking for a singular form is pointless.
  213.      */
  214.  
  215.     if (!alt)
  216.         alt = makesingular(inp);
  217.     else
  218.         if (user_typed_name)
  219.             (void) lcase(alt);
  220.  
  221.     /* skip first record; read second */
  222.     txt_offset = 0L;
  223.     if (!fgets(buf, BUFSZ, fp) || !fgets(buf, BUFSZ, fp)) {
  224.         impossible("can't read 'data' file");
  225.         (void) fclose(fp);
  226.         return;
  227.     } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset <= 0)
  228.         goto bad_data_file;
  229.  
  230.     /* look for the appropriate entry */
  231.     while (fgets(buf,BUFSZ,fp)) {
  232.         if (*buf == '.') break;  /* we passed last entry without success */
  233.  
  234.         if (!digit(*buf)) {
  235.         if (!(ep = index(buf, '\n'))) goto bad_data_file;
  236.         *ep = 0;
  237.         if (pmatch(buf, inp) || (alt && pmatch(buf, alt))) {
  238.             found_in_file = TRUE;
  239.             break;
  240.         }
  241.         }
  242.     }
  243.     }
  244.  
  245.     if(found_in_file) {
  246.     long entry_offset;
  247.     int  entry_count;
  248.     int  i;
  249.  
  250.     /* skip over other possible matches for the info */
  251.     do {
  252.         if (!fgets(buf, BUFSZ, fp)) goto bad_data_file;
  253.     } while (!digit(*buf));
  254.     if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) {
  255. bad_data_file:    impossible("'data' file in wrong format");
  256.         (void) fclose(fp);
  257.         return;
  258.     }
  259.  
  260.     if (user_typed_name || yn("More info?") == 'y') {
  261.         winid datawin;
  262.  
  263.         if (fseek(fp, txt_offset + entry_offset, SEEK_SET) < 0) {
  264.         pline("? Seek error on 'data' file!");
  265.         (void) fclose(fp);
  266.         return;
  267.         }
  268.         datawin = create_nhwindow(NHW_TEXT);
  269.         for (i = 0; i < entry_count; i++) {
  270.         if (!fgets(buf, BUFSZ, fp)) goto bad_data_file;
  271.         if ((ep = index(buf, '\n')) != 0) *ep = 0;
  272.         if (index(buf+1, '\t') != 0) (void) tabexpand(buf+1);
  273.         putstr(datawin, 0, buf+1);
  274.         }
  275.         display_nhwindow(datawin, FALSE);
  276.         destroy_nhwindow(datawin);
  277.     }
  278.     } else if (user_typed_name)
  279.     pline("I don't have any information on those things.");
  280.  
  281.     (void) fclose(fp);
  282. }
  283.  
  284. static int
  285. do_look(quick)
  286.     boolean quick;    /* use cursor && don't search for "more info" */
  287. {
  288.     char    out_str[BUFSZ], look_buf[BUFSZ];
  289.     const char    *firstmatch = 0;
  290.     int     i;
  291.     int     sym;        /* typed symbol or converted glyph */
  292.     int        found;        /* count of matching syms found */
  293.     coord   cc;            /* screen pos of unknown glyph */
  294.     boolean save_verbose;    /* saved value of flags.verbose */
  295.     boolean from_screen;    /* question from the screen */
  296.     boolean need_to_look;    /* need to get explan. from glyph */
  297.     static const char *mon_interior = "the interior of a monster";
  298.  
  299. #ifdef GCC_WARN
  300.     sym = 0;
  301. #endif
  302.  
  303.     if (quick) {
  304.     from_screen = TRUE;    /* yes, we want to use the cursor */
  305.     } else {
  306.     i = ynq("Specify unknown object by cursor?");
  307.     if (i == 'q') return 0;
  308.     from_screen = (i == 'y');
  309.     }
  310.  
  311.     if (from_screen) {
  312.     cc.x = u.ux;
  313.     cc.y = u.uy;
  314.     } else {
  315.     getlin("Specify what? (type the word)", out_str);
  316.     if (out_str[0] == '\033')
  317.         return 0;
  318.  
  319.     if (out_str[1]) {    /* user typed in a complete string */
  320.         checkfile(out_str, TRUE);
  321.         return 0;
  322.     }
  323.     sym = out_str[0];
  324.     }
  325.  
  326.     /* Save the verbose flag, we change it later. */
  327.     save_verbose = flags.verbose;
  328.     flags.verbose = flags.verbose && !quick;
  329.     /*
  330.      * The user typed one letter, or we're identifying from the screen.
  331.      */
  332.     do {
  333.     /* Reset some variables. */
  334.     need_to_look = FALSE;
  335.     found = 0;
  336.     out_str[0] = '\0';
  337.  
  338.     if (from_screen) {
  339.         int glyph;    /* glyph at selected position */
  340.  
  341.         if (flags.verbose)
  342.         pline("Please move the cursor to an unknown object.");
  343.         else
  344.         pline("Pick an object.");
  345.  
  346.         getpos(&cc, FALSE, "an unknown object");
  347.         if (cc.x < 0) {
  348.         flags.verbose = save_verbose;
  349.         return 0;    /* done */
  350.         }
  351.         flags.verbose = FALSE;    /* only print long question once */
  352.  
  353.         /* Convert the glyph at the selected position to a symbol. */
  354.         glyph = glyph_at(cc.x,cc.y);
  355.         if (glyph_is_cmap(glyph)) {
  356.         sym = showsyms[glyph_to_cmap(glyph)];
  357.         } else if (glyph_is_trap(glyph)) {
  358.         sym = showsyms[(glyph_to_trap(glyph) == WEB) ? S_web : S_trap];
  359.         } else if (glyph_is_object(glyph)) {
  360.         sym = oc_syms[objects[glyph_to_obj(glyph)].oc_class];
  361.         } else if (glyph_is_monster(glyph)) {
  362.         sym = monsyms[mons[glyph_to_mon(glyph)].mlet];
  363.         } else if (glyph_is_swallow(glyph)) {
  364.         sym = showsyms[glyph_to_swallow(glyph)+S_sw_tl];
  365.         } else {
  366.         impossible("do_look:  bad glyph %d at (%d,%d)",
  367.                         glyph, (int)cc.x, (int)cc.y);
  368.         sym = ' ';
  369.         }
  370.     }
  371.  
  372.     /*
  373.      * Check all the possibilities, saving all explanations in a buffer.
  374.      * When all have been checked then the string is printed.
  375.      */
  376.  
  377.     /* Check for monsters */
  378.     for (i = 0; i < MAXMCLASSES; i++) {
  379.         if (sym == (from_screen ? monsyms[i] : def_monsyms[i])) {
  380.         need_to_look = TRUE;
  381.         if (!found) {
  382.             Sprintf(out_str, "%c       %s", sym, an(monexplain[i]));
  383.             firstmatch = monexplain[i];
  384.             found++;
  385.         } else {
  386.             found += append_str(out_str, an(monexplain[i]));
  387.         }
  388.         }
  389.     }
  390.  
  391.     /*
  392.      * Special case: if identifying from the screen, and we're swallowed,
  393.      * and looking at something other than our own symbol, then just say
  394.      * "the interior of a monster".
  395.      */
  396.     if (u.uswallow && from_screen && is_swallow_sym((uchar) sym)) {
  397.         if (!found) {
  398.         Sprintf(out_str, "%c       %s", sym, mon_interior);
  399.         firstmatch = mon_interior;
  400.         } else {
  401.         found += append_str(out_str, mon_interior);
  402.         }
  403.         need_to_look = TRUE;
  404.     }
  405.  
  406.     /* Now check for objects */
  407.     for (i = 1; i < MAXOCLASSES; i++) {
  408.         if (sym == (from_screen ? oc_syms[i] : def_oc_syms[i])) {
  409.         need_to_look = TRUE;
  410.         if (!found) {
  411.             Sprintf(out_str, "%c       %s", sym, an(objexplain[i]));
  412.             firstmatch = objexplain[i];
  413.             found++;
  414.         } else {
  415.             found += append_str(out_str, an(objexplain[i]));
  416.         }
  417.         }
  418.     }
  419.  
  420.     /* Now check for graphics symbols */
  421.     for (i = 0; i < MAXPCHARS; i++) {
  422.         if (sym == (from_screen ? showsyms[i] : defsyms[i].sym) &&
  423.                         (*defsyms[i].explanation)) {
  424.         if (!found) {
  425.             Sprintf(out_str, "%c       %s",
  426.                         sym, an(defsyms[i].explanation));
  427.             firstmatch = defsyms[i].explanation;
  428.             found++;
  429.         } else if (!u.uswallow) {
  430.             found += append_str(out_str, an(defsyms[i].explanation));
  431.         }
  432.  
  433.         if (i == S_altar || i == S_trap || i == S_web)
  434.             need_to_look = TRUE;
  435.         }
  436.     }
  437.  
  438.     /*
  439.      * If we are looking at the screen, follow multiple posibilities or
  440.      * an ambigious explanation by something more detailed.
  441.      */
  442.     if (from_screen) {
  443.         if (found > 1 || need_to_look) {
  444.         lookat(cc.x, cc.y, look_buf);
  445.         firstmatch = look_buf;
  446.         if (*firstmatch) {
  447.             char temp_buf[BUFSZ];
  448.             Sprintf(temp_buf, " (%s)", firstmatch);
  449.             (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1);
  450.             found = 1;    /* we have something to look up */
  451.         }
  452.         }
  453.     }
  454.  
  455.     /* Finally, print out our explanation. */
  456.     if (found) {
  457.         pline(out_str);
  458.         /* check the data file for information about this thing */
  459.         if (found == 1 && !quick && flags.help) {
  460.         char temp_buf[BUFSZ];
  461.         Strcpy(temp_buf, firstmatch);
  462.         checkfile(temp_buf, FALSE);
  463.         }
  464.     } else {
  465.         pline("I've never heard of such things.");
  466.     }
  467.  
  468.     } while (from_screen && !quick);
  469.  
  470.     flags.verbose = save_verbose;
  471.     return 0;
  472. }
  473.  
  474.  
  475. int
  476. dowhatis()
  477. {
  478.     return do_look(FALSE);
  479. }
  480.  
  481. int
  482. doquickwhatis()
  483. {
  484.     return do_look(TRUE);
  485. }
  486.  
  487. int
  488. doidtrap()
  489. {
  490.     register struct trap *trap;
  491.     register int x,y;
  492.  
  493.     if(!getdir(NULL)) return 0;
  494.     x = u.ux + u.dx;
  495.     y = u.uy + u.dy;
  496.     for(trap = ftrap; trap; trap = trap->ntrap)
  497.         if(trap->tx == x && trap->ty == y && trap->tseen) {
  498.             if(u.dz) {
  499.             if(u.dz < 0 && trap->ttyp == TRAPDOOR)
  500.                 continue;
  501.                 if(u.dz > 0 && trap->ttyp == ROCKTRAP)
  502.                 continue;
  503.             }
  504.             pline("That is a%s.",
  505.               traps[ Hallucination ? rn1(TRAPNUM-3, 3) :
  506.                 trap->ttyp]);
  507.             return 0;
  508.         }
  509.     pline("I can't see a trap there.");
  510.     return 0;
  511. }
  512.  
  513. int
  514. dowhatdoes()
  515. {
  516.     FILE *fp;
  517.     char bufr[BUFSZ+6];
  518.     register char *buf = &bufr[6], *ep, q, ctrl, meta;
  519.  
  520.     fp = fopen_datafile(CMDHELPFILE, "r");
  521.     if (!fp) {
  522.         pline("Cannot open data file!");
  523.         return 0;
  524.     }
  525.  
  526. #if defined(UNIX) || defined(VMS)
  527.     introff();
  528. #endif
  529.     q = yn_function("What command?", NULL, '\0');
  530. #if defined(UNIX) || defined(VMS)
  531.     intron();
  532. #endif
  533.     ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
  534.     meta = ((0x80 & q) ? (0x7f & q) : 0);
  535.     while(fgets(buf,BUFSZ,fp))
  536.         if ((ctrl && *buf=='^' && *(buf+1)==ctrl) ||
  537.         (meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) ||
  538.         *buf==q) {
  539.         ep = index(buf, '\n');
  540.         if(ep) *ep = 0;
  541.         if (ctrl && buf[2] == '\t'){
  542.             buf = bufr + 1;
  543.             (void) strncpy(buf, "^?      ", 8);
  544.             buf[1] = ctrl;
  545.         } else if (meta && buf[3] == '\t'){
  546.             buf = bufr + 2;
  547.             (void) strncpy(buf, "M-?     ", 8);
  548.             buf[2] = meta;
  549.         } else if(buf[1] == '\t'){
  550.             buf = bufr;
  551.             buf[0] = q;
  552.             (void) strncpy(buf+1, "       ", 7);
  553.         }
  554.         pline("%s", buf);
  555.         (void) fclose(fp);
  556.         return 0;
  557.         }
  558.     pline("I've never heard of such commands.");
  559.     (void) fclose(fp);
  560.     return 0;
  561. }
  562.  
  563. /* data for help_menu() */
  564. static const char *help_menu_items[] = {
  565.     "Information available:",
  566.     "",
  567.     "a.  Long description of the game and commands.",
  568.     "b.  List of game commands.",
  569.     "c.  Concise history of NetHack.",
  570.     "d.  Info on a character in the game display.",
  571.     "e.  Info on what a given key does.",
  572.     "f.  List of game options.",
  573.     "g.  Longer explanation of game options.",
  574.     "h.  List of extended commands.",
  575.     "i.  The NetHack license.",
  576. #ifdef PORT_HELP
  577.     "j.  %s-specific help and commands.",
  578. #endif
  579. #ifdef WIZARD
  580. # ifdef PORT_HELP
  581. # define WIZHLP_SLOT 12    /* assumed to be next to last by code below */
  582.     "k.  List of wizard-mode commands.",
  583. # else
  584. # define WIZHLP_SLOT 11    /* assumed to be next to last by code below */
  585.     "j.  List of wizard-mode commands.",
  586. # endif
  587. #endif
  588.     "",
  589.     NULL
  590. };
  591.  
  592. static char
  593. help_menu()
  594. {
  595.     winid tmpwin = create_nhwindow(NHW_MENU);
  596. #ifdef PORT_HELP
  597.     char helpbuf[QBUFSZ];
  598. #endif
  599.     char hc;
  600.     register int i;
  601.  
  602.     start_menu(tmpwin);
  603. #ifdef WIZARD
  604.     if (!wizard) help_menu_items[WIZHLP_SLOT] = "",
  605.              help_menu_items[WIZHLP_SLOT+1] = NULL;
  606. #endif
  607.     for (i = 0; help_menu_items[i]; i++)
  608. #ifdef PORT_HELP
  609.         /* port-specific line has a %s in it for the PORT_ID */
  610.         if (index(help_menu_items[i], '%')) {
  611.         Sprintf(helpbuf, help_menu_items[i], PORT_ID);
  612.         add_menu(tmpwin, helpbuf[0], 0, helpbuf);
  613.         } else
  614. #endif
  615.         {
  616.         add_menu(tmpwin, i ? *help_menu_items[i] : 0, 0,
  617.              help_menu_items[i]);
  618.         }
  619.     end_menu(tmpwin, '\033', "\033", "Select one item or ESC: ");
  620.     hc = select_menu(tmpwin);
  621.     destroy_nhwindow(tmpwin);
  622.     return hc;
  623. }
  624.  
  625. int
  626. dohelp()
  627. {
  628.     char hc = help_menu();
  629.     if (!index(quitchars, hc)) {
  630.         switch(hc) {
  631.             case 'a':  display_file(HELP, TRUE);  break;
  632.             case 'b':  display_file(SHELP, TRUE);  break;
  633.             case 'c':  (void) dohistory();  break;
  634.             case 'd':  (void) dowhatis();  break;
  635.             case 'e':  (void) dowhatdoes();  break;
  636.             case 'f':  option_help();  break;
  637.             case 'g':  display_file(OPTIONFILE, TRUE);  break;
  638.             case 'h':  (void) doextlist();  break;
  639.             case 'i':  display_file(LICENSE, TRUE);  break;
  640. #ifdef PORT_HELP
  641.             case 'j':  port_help();  break;
  642. # ifdef WIZARD
  643.             case 'k':  display_file(DEBUGHELP, TRUE);  break;
  644. # endif
  645. #else
  646. # ifdef WIZARD
  647.             case 'j':  display_file(DEBUGHELP, TRUE);  break;
  648. # endif
  649. #endif
  650.         }
  651.     }
  652.     return 0;
  653. }
  654.  
  655. int
  656. dohistory()
  657. {
  658.     display_file(HISTORY, TRUE);
  659.     return 0;
  660. }
  661.  
  662. /*pager.c*/
  663.